你真的懂布局吗?

今天在复习 CSS 知识,对于 CSS 相关的知识,个人觉得面试考的最多的可能就是 CSS 盒模型和布局相关了。而对于布局常考的基本上是:三栏布局、左右布局、垂直居中、BFC、flex布局相关等。

CSS 盒模型

CSS 中的盒子模型包括 IE 盒子模型和标准的 W3C 盒子模型。

其盒子模型还是要归宗于 box-sizing 的属性即:

1
2
box-sizing: border-box; //IE盒子模型
box-sizing: content-box; //标准盒子模型,默认值

所谓的标准盒子模型 (border-box):width = 左右border+左右padding+contentwidth,而 IE 盒子模型 (border-box): width = content+padding+border,元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。

三栏布局

什么是三栏布局?一般来说我们指的三栏布局是左右宽度固定,中间部分自适应。实现三栏布局的方法有好多种,我整理了一下分五种方式实现,但是实现方法就不止 5 种了,我这里整理了 8 种方案,方便大家学习与参考:

浮动布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!--浮动布局  -->
<section class="layout float">
<style>
*{
padding: 0;
margin: 0;
}
.layout article div{
min-height: 100px;
}
.layout.float .left{
float:left;
width:300px;
background: red;
}
.layout.float .center{
background: yellow;
}
.layout.float .right{
float:right;
width:300px;
background: blue;
}
</style>
<h1>三栏布局</h1>
<article class="left-right-center">
<div class="left"></div>
<div class="right"></div>
<div class="center">
<h2>浮动解决方案</h2>
1.这是三栏布局的浮动解决方案;
2.这是三栏布局的浮动解决方案;
</div>
</article>
</section>

浮动布局的优点就是比较简单,兼容性也比较好。只要清除浮动做的好,一般是没有什么问题的,也是用的最多的三栏布局方式,后面说的圣杯布局与双飞翼布局也是基于浮动布局来实现的。

这里顺带说一下清除浮动的方式,一般有四种:

  • 利用clear样式
  • 在父元素结束标签之前插入清除浮动的块级元素
  • 利用伪元素:after
  • 利用overflow清除浮动

绝对定位布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!-- 绝对布局 -->
<section class="layout absolute">
<style>
*{
padding: 0;
margin: 0;
}
.layout article div{
min-height: 100px;
}
.layout.absolute .left-center-right>div{
position: absolute;
}
.layout.absolute .left{
left:0;
width: 300px;
background: red;
}
.layout.absolute .center{
left: 300px;
right: 300px;
background: yellow;
}
.layout.absolute .right{
right:0;
width: 300px;
background: blue;
}
</style>
<h1>三栏布局</h1>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h2>绝对定位解决方案</h2>
1.这是三栏布局的绝对定位解决方案;
2.这是三栏布局的绝对定位解决方案;
</div>
<div class="right"></div>
</article>
</section>

绝对定位布局优点,很快捷,设置很方便,而且也不容易出问题。

缺点就是,绝对定位是脱离文档流的,意味着下面的所有子元素也会脱离文档流,这就导致了这种方法的有效性和可使用性是比较差的。

flex布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!-- flexbox布局 -->
<section class="layout flexbox">
<style>
*{
padding: 0;
margin: 0;
}
.layout article div{
min-height: 100px;
}
.layout.flexbox{
margin-top: 100px;
}
.layout.flexbox .left-center-right{
display: flex;
}
.layout.flexbox .left{
width: 300px;
background: red;
}
.layout.flexbox .center{
flex:1;
background: yellow;
}
.layout.flexbox .right{
width: 300px;
background: blue;
}
</style>
<h1>三栏布局</h1>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h2>flexbox解决方案</h2>
1.这是三栏布局的felx解决方案;
2.这是三栏布局的flex解决方案;
</div>
<div class="right"></div>
</article>
</section>

felxbox 布局是比较完美的一个实现有关固定宽度和自适应宽度布局的方案。目前移动端的布局也都是用 flexbox。

felxbox 的缺点就是不能兼容IE8及以下浏览器。

表格布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!-- 表格布局 -->
<section class="layout table">
<style>
*{
padding: 0;
margin: 0;
}
.layout article div{
min-height: 100px;
}
.layout.table .left-center-right{
width:100%;
height: 100px;
display: table;
}
.layout.table .left-center-right>div{
display: table-cell;
}
.layout.table .left{
width: 300px;
background: red;
}
.layout.table .center{
background: yellow;
}
.layout.table .right{
width: 300px;
background: blue;
}
</style>
<h1>三栏布局</h1>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h2>表格布局解决方案</h2>
1.这是三栏布局的表格解决方案;
2.这是三栏布局的表格解决方案;
</div>
<div class="right"></div>
</article>
</section>

表格布局在布局的时候我们可能不常用,但是表格布局的兼容性很好,在 flex 布局不兼容的时候,可以尝试表格布局。

表格布局也是有缺点的,当其中一个单元格高度超出的时候,两侧的单元格也是会跟着一起变高的,而有时候这种效果不是我们想要的,个人认为这也是它的优点。

网格布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!-- 网格布局 -->
<section class="layout grid">
<style>
*{
padding: 0;
margin: 0;
}
.layout article div{
min-height: 100px;
}
.layout.grid .left-center-right{
width:100%;
display: grid;
grid-template-rows: 100px;
grid-template-columns: 300px auto 300px;
}
.layout.grid .left{
background: red;
}
.layout.grid .center{
background: yellow;
}
.layout.grid .right{
background: blue;
}
</style>
<h1>三栏布局</h1>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h2>网格布局解决方案</h2>
1.这是三栏布局的网格布局解决方案;
2.这是三栏布局的网格布局解决方案;
</div>
<div class="right"></div>
</article>
</section>

网格布局也是新出的一种布局方式,功能强大,可以用网格布局实现瀑布流布局,响应式等布局等,这里用到的只是最基本的使用。

缺点是兼容性不是很好,不兼容IE,因此现在使用还不是很广泛。

圣杯布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<!-- 圣杯布局 -->
<section class="layout grail">
<style>
*{
padding: 0;
margin: 0;
}
.layout article div{
min-height: 100px;
}
.layout.grail .left-center-right{
padding: 0 300px;
}
.layout.grail .left-center-right:after{
display: block;
content: '';
font-size: 0;
height: 0;
clear: both;
zoom: 1;
}
.layout.grail .center {
float: left;
width: 100%;
background-color: yellow;
height: 100px;
overflow: hidden;
}
.layout.grail .left {
float: left;
width: 300px;
height: 100px;
background-color: red;
margin-left: -100%;
position: relative;
left: -300px;
}
.layout.grail .right {
float: left;
margin-left: -300px;
width: 300px;
height: 100px;
background-color: blue;
position: relative;
right: -300px;
}
</style>
<h1>圣杯布局</h1>
<article class="left-center-right">
<div class="center">
<h2>圣杯布局解决方案</h2>
1.这是圣杯布局的解决方案;
2.这是圣杯布局的解决方案;
</div>
<div class="left"></div>
<div class="right"></div>
</article>
</section>

圣杯布局基于浮动方案实现的,是 Kevin Cornell 在 2006 年提出的一个布局模型概念。

双飞翼布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!-- 双飞翼布局 -->
<section class="layout fly">
<style>
*{
padding: 0;
margin: 0;
}
.layout article div{
min-height: 100px;
}
.layout.fly .center {
float: left;
width: 100%;
}
.layout.fly .main {
height: 100px;
margin-left: 300px;
margin-right: 300px;
background-color: yellow;
}
.layout.fly .center::after {
display: block;
content: '';
font-size: 0;
height: 0;
clear: both;
zoom: 1;
}
.layout.fly .left {
float: left;
height: 100px;
width: 300px;
margin-left: -100%;
background-color: red;
}
.layout.fly .right {
width: 300px;
height: 100px;
float: left;
margin-left: -300px;
background-color: blue;
}
</style>
<h1>双飞翼布局</h1>
<article class="left-center-right">
<div class="center">
<div class="main">
<h2>双飞翼布局解决方案</h2>
1.这是双飞翼布局的解决方案;
2.这是双飞翼布局的解决方案;
</div>
</div>
<div class="left"></div>
<div class="right"></div>
</article>
</section>

双飞翼布局也是基于浮动实现的,最早是由淘宝的玉伯大大提出来的。

自己发现的布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!-- 自己发现的布局 -->
<section class="layout self">
<style>
.layout.self .left-center-right{

}
.layout.self .left-center-right:after{
display: block;
content: '';
font-size: 0;
height: 0;
clear: both;
zoom: 1;
}
.layout.self .center {
float: left;
width: 100%;
background-color: yellow;
height: 100px;
box-sizing: border-box;
padding: 0 300px;
}
.layout.self .left {
float: left;
width: 300px;
height: 100px;
background-color: red;
margin-left: -100%;
}
.layout.self .right {
float: left;
margin-left: -300px;
width: 300px;
height: 100px;
background-color: blue;
}
</style>
<h1>自己发现的布局</h1>
<article class="left-center-right">
<div class="center">
<h2>自己发现的布局解决方案</h2>
1.这是自己发现的布局解决方案;
2.这是自己发现的布局解决方案;
</div>
<div class="left"></div>
<div class="right"></div>
</article>
</section>

圣杯布局与双飞翼布局很是相似,只是对于中间部分内容遮蔽的处理方式不同,我在整理以上两个布局的时候,开始是自己根据自己的记忆直接写的,然后自己考虑了一下,在中间内容遮蔽的处理方式上,采用:box-sizing: border-box;padding: 0 300px;

个人觉得这样 CSS 代码简单了许多,缺点是如果布局涉及到 border 和 padding 的处理时候,中间和两边的盒模型不一样,需要特别注意一下。

八种实现方式效果图如下:

这里写图片描述

左右布局

类似于上面的三栏布局,这里例句一下两栏布局的实现方案,即左边宽度固定,右边自适应:

浮动实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<section class="layout float">
<style type="text/css">
*{
padding: 0;
margin: 0;
}
.layout.float .left-right{
height: 100px;
}
.layout.float .left{
width: 100px;
height: 100px;
float: left;
background-color: #0000FF;
}
.layout.float .right{
width: 100%;
height: 100px;
background-color: #FF0000;
}
</style>
<h1>两栏布局</h1>
<div class="left-right">
<div class="left"></div>
<div class="right">这是利用浮动实现</div>
</div>
</section>

flex 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<section class="layout flex">
<style type="text/css">
*{
padding: 0;
margin: 0;
}
.layout.flex .left-right{
height: 100px;
display: flex;
}
.layout.flex .left{
width: 100px;
height: 100px;
background-color: #0000FF;
}
.layout.flex .right{
flex: 1;
height: 100px;
background-color: #FF0000;
}
</style>
<h1>两栏布局</h1>
<div class="left-right">
<div class="left"></div>
<div class="right">这是利用flex实现</div>
</div>
</section>

使用 calc() 函数实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<section class="layout calc">
<style type="text/css">
*{
padding: 0;
margin: 0;
}
.layout.calc .left-right{
height: 100px;
}
.layout.calc .left{
width: 100px;
height: 100px;
float: left;
background-color: #0000FF;
}
.layout.calc .right{
width: calc(100% - 100px);
float: left;
height: 100px;
background-color: #FF0000;
}
</style>
<h1>两栏布局</h1>
<div class="left-right">
<div class="left"></div>
<div class="right">这是利用calc实现</div>
</div>
</section>

使用负 margin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<section class="layout margin">
<style type="text/css">
*{
padding: 0;
margin: 0;
}
.layout.margin .left-right{
height: 100px;
padding-left: 100px;
}
.layout.margin .right{
width: 100%;
float: left;
height: 100px;
background-color: #FF0000;
}
.layout.margin .left{
width: 100px;
height: 100px;
float: left;
margin-left: -100%;
background-color: #0000FF;
position: relative;
left: -100px;
}
</style>
<h1>两栏布局</h1>
<div class="left-right">
<div class="right">这是利用负margin实现</div>
<div class="left"></div>
</div>
</section>

网格布局的实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<section class="layout grid">
<style type="text/css">
*{
padding: 0;
margin: 0;
}
.layout.grid .left-right{
height: 100px;
display: grid;
grid-template-rows: 100px;
grid-template-columns: 100px auto;
}
.layout.grid .right{
height: 100px;
background-color: #FF0000;
}
.layout.grid .left{
height: 100px;
background-color: #0000FF;
}
</style>
<h1>两栏布局</h1>
<div class="left-right">
<div class="left"></div>
<div class="right">这是利用网格布局实现</div>
</div>
</section>

五种方式实现效果图如下:

这里写图片描述

这里只列举了 5 种实现方式,但是细心的你肯定会发现,肯定不仅仅只有这四种,类比于上面三栏布局的方式,就至少还可以再实现 3 种:绝对定位,类比双飞翼布局,box-sizing 方式等等,这里就不在列举了。

垂直居中

关于垂直居中,如果元素宽高都知道,也有炒鸡多中。这里只说内部元素宽高不确定的情况:

表格布局实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<section class="layout table">
<style type="text/css">
.layout.table .main{
text-align: center;
width: 300px;
height: 100px;
display: table-cell;
vertical-align: middle;
background-color: #FFFF00;
}
.layout.table .content{
display: inline-block;
vertical-align: middle;
background-color: #FF0000;
}
</style>
<h1>垂直居中</h1>
<div class="main">
<div class="content">表格布局实现方式</div>
</div>
</section>

flex 布局实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<section class="layout flex">
<style type="text/css">
.layout.flex .main{
width: 300px;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
background-color: #FFFF00;
}
.layout.flex .content{
background-color: #FF0000;
}
</style>
<h1>垂直居中</h1>
<div class="main">
<div class="content">flex布局实现方式</div>
</div>
</section>

translate 实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<section class="layout transform">
<style type="text/css">
.layout.transform .main{
width: 300px;
height: 100px;
position: relative;
background-color: #FFFF00;
}
.layout.transform .content{
background-color: #FF0000;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
</style>
<h1>垂直居中</h1>
<div class="main">
<div class="content">transform布局实现方式</div>
</div>
</section>

三种方式实现效果图如下:

这里写图片描述

BFC 相关

在解释 BFC 是什么之前,需要先介绍 Box、Formatting Context的概念。

Box: CSS布局的基本单位

Box 是 CSS 布局的对象和基本单位,直观点来说,就是一个页面是由很多个 Box 组成的。元素的类型和 display 属性,决定了这个 Box 的类型。 不同类型的 Box, 会参与不同的 Formatting Context(一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。让我们看看有哪些盒子:

  • block-level box:display 属性为 block, list-item, table 的元素,会生成 block-level box。并且参与 block fomatting context;
  • inline-level box:display 属性为 inline, inline-block, inline-table 的元素,会生成 inline-level box。并且参与 inline formatting context;
  • run-in box: css3 中才有, 这儿先不介绍了。

Formatting context

Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。

CSS2.1 中只有 BFC 和 IFC, CSS3 中还增加了 GFC 和 FFC。

什么是 BFC?

BFC的基本概念:块级格式化上下文,它是指一个独立的块级渲染区域,只有 block-level box 参与,该区域拥有一套渲染规则来约束块级盒子的布局,且与区域外部无关。

BFC的生成:CSS2.1 中规定满足下列 CSS 声明之一的元素便会生成 BFC:

  • 根元素(即html本身就是一个 BFC)
  • float 的值不为 none
  • overflow 的值不为 visible
  • display 的值为 inline-block、table-cell、table-caption
  • position 的值为 absolute 或 fixed

BFC 的约束规则(原理):

  1. 内部的 Box 会在垂直方向上一个接一个的放置,属于同一个 BFC 的两个相邻 Box 的 margin 会发生重叠
  2. 垂直方向上的距离由 margin 决定。(完整的说法是:属于同一个 BFC 的两个相邻 Box 的 margin 会发生重叠,与方向无关,给子元素再加一个父元素,父元素创建一个 BFC 即可解决)
  3. 每个元素的左外边距与包含块的左边界相接触(从左向右),即使浮动元素也是如此。(这说明 BFC 中子元素不会超出他的包含块,而 position 为 absolute 的元素可以超出他的包含块边界)
  4. BFC 的区域不会与 float 的元素区域重叠(一个固定宽度浮动,一个只设高度且创建 BFC 即可)
  5. 计算 BFC 的高度时,浮动子元素也参与计算(创建 BFC 清除浮动原理,例如:子元素浮动,父元素 overflow:auto)
  6. BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然

flex 布局

flex 布局这里偷个懒,引用 阮一峰老师的介绍地址:Flex 布局教程:语法篇,里面从各方面都说的非常详细啦。



完~